/**
  * 
  */
 package cp1300.ass1.trafficlight;
 
 import java.util.ArrayList;
 import java.util.Iterator;
 
 /**
  * @author MorbidSaint
  *
  */
 /**
  * Class which displays the 2 dim array on the screen
  */
 public class Grid {
 
     /**
      * Display Grid arrayvariable
      */
     char displayScreen[][] = new char[50][50];
     /**
      * ArrayList of Cars
      */
     ArrayList<Car> oCars = new ArrayList<Car>();
     
     /**
      * Traffic Light Varible - LTR
      */
     TrafficLight oLTRTrafficLight = new TrafficLight();
     /**
      * Traffic Light Variable - TTB
      */
     TrafficLight oTTBTrafficLight = new TrafficLight();    
     
     /**
      * User entered choices
      */
     UserChoice oUserChoice;
     
     /**
      * Iteration Run for a simulation run
      */
     Integer oIterationRun = new Integer(0);
     
     /**
      * Time waited for the signal.<br/>
      * Not used now.
      */
     int timeWaited = 0;
     
     /**
      * Number of vertical cars for any simulation cycle
      */
     int iVerticalCars = 0;
     
     /**
      * Number of horizontal cars for any simulation cycle
      */
     int iHorizontalCars = 0;
     
 /**
  * 
  * @param oUserChoice User Entered Information
  */
     public Grid(UserChoice oUserChoice) {
         // TODO Auto-generated constructor stub
         this.oUserChoice = oUserChoice;
         
         //Setting Vertical Lane Traffic Light
         oLTRTrafficLight.setXpos(GridConstants.HORIZONTAL_LANE_START-1);
         oLTRTrafficLight.setYpos(GridConstants.VERTICAL_LANE_START+oUserChoice.getVerticalLanes()+1);
         oLTRTrafficLight.setSignal('G');
 
         //Setting Horizontal Lane Traffic Light        
         oTTBTrafficLight.setXpos(GridConstants.HORIZONTAL_LANE_START+oUserChoice.getHorizontalLanes()+1);
         oTTBTrafficLight.setYpos(GridConstants.VERTICAL_LANE_START-1);
         oTTBTrafficLight.setSignal('G');
         
         //Initial Cars        
         if(oCars.size()==0){
             oCars.add(new Car(GridConstants.HORIZONTAL_LANE_START+1,0,GridConstants.LEFT_RIGHT,false));            
             oCars.add(new Car(0,GridConstants.VERTICAL_LANE_START+1,GridConstants.TOP_BOTTOM,false));        
         }
         
     }
 
     
     /**
      * Run the stimulation 'x' number of times
      * 
      */
     public void startSimulation(){
         
         for(int i=0;i<(oUserChoice.getNumberOfSimulationTimes()*30)+timeWaited;i++){
             oIterationRun = i;
             updateCarIterationValue(i);
             //Clearing the screen
             clear();                        
             drawGrid();            
         }
     }
     
     /**
      * Method to set the iteration value of the list of cars
      * @param i not used
      */
     private void updateCarIterationValue(int i) {
         // TODO Auto-generated method stub
         Iterator<Car> oCarIterator = oCars.iterator();
         while(oCarIterator.hasNext()){
             Car oTempCar = oCarIterator.next();
             oTempCar.setIterationRun(oTempCar.getIterationRun()+1);
         }
         
     }
 
 
     /**
      * Method to draw the grid on the console.
      */
     public void drawGrid(){
         
         for(int i=0;i<GridConstants.GRID_XCOLS;i++){
             for(int j=0;j<GridConstants.GRID_YCOLS;j++){
                 
                 boolean isVerticalSpacing = true;
                 boolean isHorSpacing = true;
                 
                 if(j>=GridConstants.VERTICAL_LANE_BREAK && j<=GridConstants.VERTICAL_LANE_BREAK+oUserChoice.getVerticalLanes() ){
                         isVerticalSpacing =false;
                 }
                 
                 if(i>=GridConstants.HORIZONTAL_LANE_START && i<=GridConstants.HORIZONTAL_LANE_START+oUserChoice.getHorizontalLanes()){
                     isHorSpacing = false;
                 }
                 
                 if((i==GridConstants.HORIZONTAL_LANE_START || i==GridConstants.HORIZONTAL_LANE_START+oUserChoice.getHorizontalLanes()) && isVerticalSpacing){
                     displayScreen[i][j]='-';    
                 }else if((j==GridConstants.VERTICAL_LANE_START || j==GridConstants.VERTICAL_LANE_START+oUserChoice.getVerticalLanes())&& isHorSpacing){
                     displayScreen[i][j]='|';
                 }else{
                     displayScreen[i][j]=' ';
                 }
                 
         
                 }
             }        
         
         //Calling the method to draw cars
         drawCars();
         
         
         //Displaying the screen
         displayGrid();
         
         //Introduce delay
         delay();
         
         //Move the cars
         moveCars();
         
     }
 
     /**
      * Move the cars on the screen
      */
 private void moveCars() {
         // TODO Auto-generated method stub
     
     
     Iterator<Car> oCarIterator = oCars.iterator();
     while(oCarIterator.hasNext()){
         Car oTempCar = oCarIterator.next();
             
         if(oTempCar.getDirection()==GridConstants.LEFT_RIGHT && oLTRTrafficLight.getSignal()!='R' && !oTempCar.isRunOver()){
             oTempCar.setYPos(oTempCar.getYPos()+1);
             if(oTempCar.getXPos()==GridConstants.GRID_XCOLS){
                 oTempCar.setRunOver(true);
                 iHorizontalCars--;
                 }
         }
         else if(oTempCar.getDirection()==GridConstants.TOP_BOTTOM && oTTBTrafficLight.getSignal()!='R' && !oTempCar.isRunOver()){
             oTempCar.setXPos(oTempCar.getXPos()+1);
             if(oTempCar.getYPos()==GridConstants.GRID_YCOLS){
                 oTempCar.setRunOver(true);
                 iVerticalCars--;
             }
         }
         
     
     }
 
     }
 
 /**
  * Clear the screen.<br>
  * Basically prints the newline character 300 times.
  */
 private void clear() {
         // TODO Auto-generated method stub
     int i = 0;
     for(i=0;i<300;i++)
     {
     System.out.println("\n");
     }
 
 }        
 
 /**
  * Delay method to introduce a delay of 1 s
  */
 
 private void delay() {
         // TODO Auto-generated method stub
     try
     {
     Thread.sleep(1000); // do nothing for 1000 miliseconds (1 second)
     }
     catch(InterruptedException e)
     {
     e.printStackTrace();
     } 
     
     }
 
 /**
  * Apply the probabilities to introduce new cars to the lane.
  */
 private void drawCars() {
         // TODO Auto-generated method stub
     
     //Adding new cars..
     /**
      * Logic: Prob 1 - car enters every space moved
      * Prob 0 - Car enters after the car has moved the complete stretch
      * Prob (0-1)  - Car enters for every iteration run % (Prob*100)
      * 
      */
     
     if(iVerticalCars<GridConstants.MAX_NO_OF_CARS){
         
         if(oIterationRun.intValue()%30==0 && oUserChoice.getPropabilityVLane()==0 ){
             oCars.add(new Car(0,GridConstants.VERTICAL_LANE_START+1,GridConstants.TOP_BOTTOM,false));
             iVerticalCars++;        
         }
         
         if(oUserChoice.getPropabilityVLane()==1){
             oCars.add(new Car(0,GridConstants.VERTICAL_LANE_START+1,GridConstants.TOP_BOTTOM,false));
             iVerticalCars++;        
         }
         
         if(oIterationRun.intValue()%((int)100*oUserChoice.getPropabilityVLane())==0){
             oCars.add(new Car(0,GridConstants.VERTICAL_LANE_START+1,GridConstants.TOP_BOTTOM,false));
             iVerticalCars++;        
         }
             
     
     }
     
     if(iHorizontalCars<GridConstants.MAX_NO_OF_CARS){
         
         if(oIterationRun.intValue()%30==0 && oUserChoice.getProbabilityHLane()==0){
             oCars.add(new Car(GridConstants.HORIZONTAL_LANE_START+1,0,GridConstants.LEFT_RIGHT,false));
             iHorizontalCars++;
         }
         
         if(oUserChoice.getProbabilityHLane()==1){
             oCars.add(new Car(GridConstants.HORIZONTAL_LANE_START+1,0,GridConstants.LEFT_RIGHT,false));
             iHorizontalCars++;        
         }
         
         if(oIterationRun.intValue()%((int)100*oUserChoice.getProbabilityHLane())==0){
             oCars.add(new Car(GridConstants.HORIZONTAL_LANE_START+1,0,GridConstants.LEFT_RIGHT,false));
             iHorizontalCars++;        
         }    
         
     }
         
     //Displaying the car on the screen
     Iterator<Car> oCarIterator = oCars.iterator();
     while(oCarIterator.hasNext()){
         Car oTempCar = oCarIterator.next();
         if(!oTempCar.isRunOver()){
             if(oTempCar.getXPos()>49) continue;
             if(oTempCar.getYPos()>49) continue;
             displayScreen[oTempCar.getXPos()][oTempCar.getYPos()] = 'c';            
         }
         
         /**
          * Changing signal based on Iteration run
          */
         if(iVerticalCars<iHorizontalCars){
             if(oTempCar.getIterationRun()==14){
                 oTTBTrafficLight.setSignal('R');
             }
             
             if(oTempCar.getIterationRun()==16){
                 oTTBTrafficLight.setSignal('G');
             }    
         }else{
             
             if(oTempCar.getIterationRun()==14){
                 oLTRTrafficLight.setSignal('R');
             }
             
             if(oTempCar.getIterationRun()==16){
                 oLTRTrafficLight.setSignal('G');
             }
         }
         
         
             
     }        
     //Updating the signal
     updateSignal();
         
     }
 
 
 private void updateSignal() {
     // TODO Auto-generated method stub    
     displayScreen[oLTRTrafficLight.getXpos()][oLTRTrafficLight.getYpos()] = oLTRTrafficLight.getSignal();
     displayScreen[oTTBTrafficLight.getXpos()][oTTBTrafficLight.getYpos()] = oTTBTrafficLight.getSignal();
     
 }
 
 /**
  * Display the grid on the console
  */
 public void displayGrid(){
     
     for(int i=0;i<GridConstants.GRID_XCOLS;i++){
         for(int j=0;j<GridConstants.GRID_YCOLS;j++){
             System.out.print(displayScreen[i][j]);
             if(j==GridConstants.GRID_YCOLS-1){
                 System.out.println();
             }
             
         }
         
     }
     
 }
 
 }
 
